package com.common.utils;

import com.common.constants.NumberConstantPool;
import com.common.interfaces.MyFunction;

import java.lang.invoke.SerializedLambda;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * bean属性获取工具类
 */
public class FieldUtil {
    /**
     * 批量获取属性名称
     *
     * @param functions
     * @param <T>
     * @return
     */
    public static <T> String[] getColumns(MyFunction[] functions) {
        String[] nameArr = new String[functions.length];
        for (int i = NumberConstantPool.ZERO; i < functions.length; i++) {
            String column = getColumn(functions[i]);
            nameArr[i] = column;
        }
        return nameArr;
    }

    /**
     * 将bean的属性的get方法，作为lambda表达式传入时，获取get方法对应的属性名称
     *
     * @param function lambda表达式，bean的属性的get方法
     * @param <T>      泛型
     * @return 属性对象
     */
    public static <T> String getColumn(MyFunction<T, ?> function) {
        // 从function取出序列化方法
        Method writeReplaceMethod;
        try {
            Class<? extends MyFunction> clazz = function.getClass();
            writeReplaceMethod = clazz.getDeclaredMethod("writeReplace");
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
        // 设置权限为可以访问
        writeReplaceMethod.setAccessible(true);
        SerializedLambda serializedLambda;
        try {
            // 从序列化方法取出序列化的lambda信息
            serializedLambda = (SerializedLambda) writeReplaceMethod.invoke(function);
        } catch (IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
        // 关闭访问权限
        writeReplaceMethod.setAccessible(false);
        // 从lambda信息取出method、field、class等
        String methodName = serializedLambda.getImplMethodName();
        // 获取第一个大写字母的下标位置
        int index = StringUtils.firstIndexOfUpperCase(methodName);
        // 确保方法是符合规范的get方法，boolean类型是is开头
        if (index < NumberConstantPool.ZERO) {
            throw new RuntimeException("get方法不符合javaBean规范");
        }
        // get方法开头为 is 或者 get，将方法名 去除is或者get，然后首字母小写，就是属性名
        String fieldName = methodName.substring(index);
        // 截取字符串的第一位
        String firstChar = fieldName.substring(NumberConstantPool.ZERO, NumberConstantPool.ONE);
        // 替换首位字符串
        fieldName = fieldName.replaceFirst(firstChar, firstChar.toLowerCase());
        // 返回最终的属性名称
        return fieldName;
    }
}
